#include "list.h"
#include <string.h>

//   HASH - TABLE
//


const int MAX_HASH_SIZE = 993;
const int MAX_HASH_WORD_SIZE = 30;
const int MAX_WORD_NUMBER = 5000;

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

int Hash_function_transform(int (*func)(char*) , char* word);

void analysis_input(FILE* input_f , header_t* hash_table , int (*func)(char*));

void Fill_hash_table(header_t* hash_table , char* word , int (*func)(char*));

void Hash_fill(header_t* hash_table , FILE* out_f);

int analysis_word(char* word , header_t* hash_table , int number);

void Hash_dtor(header_t* hash_table);

void Hash_Dump(header_t* hash_table , int print_ok_visible);

int Hash_OK(header_t* hash_table);

int Hash_one(char* word);
int Hash_two(char* word);
int Hash_three(char* word);
int Hash_four(char* word);
int Hash_five(char* word);

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#define HASH_CHECK(hash_table) if(Hash_OK(hash_table) != -1) Hash_Dump(hash_table , 1);


int main()
{

    header_t* hash_table_two   = (header_t*)calloc(MAX_HASH_SIZE , sizeof(*hash_table_two));  assert(hash_table_two);

    FILE* input_f = fopen("input.txt" , "r");                      assert(input_f);
    FILE* out_f   = fopen("out.csv" , "w");                        assert(out_f);

    analysis_input(input_f , hash_table_two , Hash_five);
    Hash_fill(hash_table_two , out_f);

    HASH_CHECK(hash_table_two);

    Hash_Dump(hash_table_two , 1);

    Hash_dtor(hash_table_two);

    return 0;

}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

int Hash_OK(header_t* hash_table)
{
    assert(hash_table);

    for(int list_number = 0; list_number < MAX_HASH_SIZE; list_number++)
    {
        if(List_OK(hash_table + list_number)) { return list_number;}
    }

    return -1; //because number of trouble list can not be -1

}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void Hash_Dump(header_t* hash_table , int print_ok_visible)
{

    assert(hash_table);

    if(Hash_OK(hash_table) != - 1)
    {

        int problem_list_number = Hash_OK(hash_table);

        printf("\n\nProblem in list %d\n\n" , problem_list_number);
        List_Dump(hash_table + problem_list_number , 1);

    }

    else
    {

        if(print_ok_visible == 1)
        {

            for(int list_number = 0; list_number < MAX_HASH_SIZE; list_number++)
            {

                printf("list number : %d\n" , list_number);
                List_Dump(hash_table + list_number , 1);
                printf("--------------------------------------------------------------------------\n");

            }

        }

    }

}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void Hash_dtor(header_t* hash_table)
{

    assert(hash_table);

    for(int i = 0; i < MAX_HASH_SIZE; i++)
    {
        List_Dtor(hash_table + i);
    }

    free(hash_table); hash_table = NULL;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void analysis_input(FILE* input_f , header_t* hash_table , int (*func)(char*) )
{

    assert(input_f);
    assert(func);
    assert(hash_table);

    int word_number = 0;
    char** text = (char**)calloc(MAX_WORD_NUMBER , sizeof(char*));

    while(true)
    {

        text[word_number] = (char*)calloc(MAX_HASH_SIZE , sizeof(char));
        int OK = fscanf(input_f , "%s" , text[word_number]);


        if(OK != 1) { break ;}

        //printf("it is going scanfing word '%s'\n" , text[word_number]);

        Fill_hash_table(hash_table , text[word_number]  , func);
        word_number++;

    }

    fseek (input_f , 0 , SEEK_SET);
    //free(text);   text = NULL;

}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


void Fill_hash_table(header_t* hash_table , char* word , int (*func)(char*))
{

    assert(hash_table);
    assert(func);
    assert(word);


    int number = (unsigned) func (word) % MAX_HASH_SIZE;

    int OK = analysis_word(word , hash_table , number);
    if(OK == 0)
    {

        List_add_element( (hash_table + number) , 1 , LEFT , word);

    }

}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

int analysis_word(char* word , header_t* hash_table , int number)
{

    assert(word);
    assert(hash_table);

    if((hash_table + number)->counter > 0)
    {

        list_elem_t* now = (hash_table + number)->first_pointer;

         while( now != NULL)
         {

            if(strcmp( (now->word_el) , word) == 0) {  return 1; }
            now = now->right_pointer;

         }

    }

    return 0;
}


//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

int Hash_one(char* word)
{

    assert(word);

    return word[0];

}

int Hash_two(char* word)
{

    assert(word);

    return 1;

}

int Hash_three(char* word)
{

    assert(word);

    return strlen(word);

}

int Hash_four(char * word)
{

    assert(word);

    int length = strlen(word);
    int sum = 0;

    for(int i = 0; i < length; i++)
    {
        sum = sum + word[i];
    }

    return sum;

}

int Hash_five(char* word)
{

    assert(word);

    int length = strlen(word);
    int value = 0;

    for(int i = 1; i < length ; i++)
    {
        value = (value<<1)^( word[i] );
    }

    return value;

}


//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void Hash_fill(header_t* hash_table , FILE* out_f)
{

    assert(hash_table);
    assert(out_f);

    for(int i = 0; i < MAX_HASH_SIZE; i++)
    {

        fprintf(out_f , "%d; " , hash_table[i].counter);

    }


    for(int i = 1; i < 2 ; i++)
    {

        fprintf(out_f, "\n");

    }

}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
























